package com.kylin.core.order.event.listener;

import com.kylin.core.commodity.query.handler.CommodityQueryHandler;
import com.kylin.core.marketing.query.handler.MarketingQueryHandler;
import com.kylin.core.order.event.repository.OrderDataHandler;
import com.kylin.core.order.query.handler.OrderTranslator;
import com.kylin.core.user.event.repository.AddressDataHandler;
import com.kylin.dal.entity.order.OrderAddressEntry;
import com.kylin.dal.entity.order.OrderLineItemEntry;
import com.kylin.dal.entity.order.OrderMainEntry;
import com.kylin.dal.entity.user.UserAddressEntry;
import com.kylin.domain.authority.command.QueryCommodityByIdCommand;
import com.kylin.domain.commodity.vo.CommodityVO;
import com.kylin.domain.coupon.vo.CouponVO;
import com.kylin.domain.marketing.command.FindMarketingCommodityCommand;
import com.kylin.domain.marketing.vo.MarketingCommodityVO;
import com.kylin.domain.order.command.PlaceOrderCommand;
import com.kylin.domain.order.vo.OrderAddressVO;
import com.kylin.domain.order.vo.OrderLineVO;
import com.kylin.domain.order.vo.OrderMainVO;
import com.kylin.shared.common.consts.Constants;
import com.kylin.shared.enums.OrderState;
import com.kylin.shared.enums.ResultCodeEnum;
import com.kylin.shared.enums.YesNoEnum;
import com.kylin.shared.exception.BusinessException;
import com.kylin.shared.utils.MappingTools;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.CommandHandler;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
 * 订单命令处理类
 * @author Damon S.
 * @version v1.0.1
 * @date 2020年05月28日 15:32
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class OrderCommandHandler {

    private final OrderTranslator orderTranslator;
    private final OrderDataHandler orderDataHandler;
    private final CommodityQueryHandler commodityQueryHandler;
    private final MarketingQueryHandler marketingQueryHandler;
    private final AddressDataHandler addressDataHandler;


    @CommandHandler
    @Transactional(rollbackFor = Exception.class)
    public Long placeOrder(PlaceOrderCommand command) {
        // 构建主订单对象
        OrderMainVO.OrderMainVOBuilder builder = OrderMainVO.builder().userId(command.getUserId());

        // 先查询要保存的订单商品是否存在
        CommodityVO commodity = commodityQueryHandler.findCommodityByCommodityId(
                QueryCommodityByIdCommand.builder().commodityId(command.getCommodityId()).build()
        );
        // 查询失败，返回
        if (CommodityVO.EMPTY.equals(commodity)) {
            log.error("购买的商品不存在[UserId:{},CommodityId:{}]", command.getUserId(), command.getCommodityId());
            throw new BusinessException(ResultCodeEnum.DATA_ERROR);
        }
        // 检查配送地址信息
        UserAddressEntry addressEntry = addressDataHandler.findUserAddressById(command.getAddressId());
        if (!addressEntry.getUserId().equals(command.getUserId()) ||
                addressEntry.getRemoved().equals(YesNoEnum.Y.getCode())) {
            log.error("指定的配送地址不正确[UserId:{},AddressId:{}]", command.getUserId(), command.getAddressId());
            throw new BusinessException(ResultCodeEnum.DATA_ERROR);
        }
        // 否则设置订单数据
        builder.productFee(commodity.getPrice() * command.getQuantity())
                .freight(command.getFreight())
                .totalFee(commodity.getPrice() * command.getQuantity() + command.getFreight())
                .couponFee(Constants.LONG_ZERO)
                .discountFee(Constants.LONG_ZERO)
                .paidFee(Constants.LONG_ZERO)
                .payMode(command.getPayMode())
                .state(OrderState.PENDING)
                .message(command.getMessage())
                .createdBy(command.getCreatedBy())
                .createdAt(MappingTools.toCurrentEpochSecond())
                .updatedBy(Constants.LONG_MINUS_ONE)
                .updatedAt(Constants.LONG_MINUS_ONE);

        // 商品是否参与了营销活动
        MarketingCommodityVO marketingCommodity = marketingQueryHandler.findMarketingCommodity(
                FindMarketingCommodityCommand.builder()
                        .commodityId(command.getCommodityId())
                        .boardId(command.getBoardId()).build()
        );
        // 参与了营销活动，则采用营销活动的价格
        if (!MarketingCommodityVO.EMPTY.equals(marketingCommodity)) {
            builder.discountFee((commodity.getPrice() - marketingCommodity.getPrice()) * command.getQuantity())
                    .paidFee(marketingCommodity.getPrice() * command.getQuantity() - command.getCouponId());
        }

        // 获取优惠券
        CouponVO coupon = CouponVO.EMPTY;
        if (!ObjectUtils.isEmpty(command.getCouponId())) {
            // TODO: 实现优惠券功能
            coupon = CouponVO.builder().build();
        }
        if (!CouponVO.EMPTY.equals(coupon)) {
            builder.couponFee(coupon.getAmount());
        }
        //  保存主订单数据
        OrderMainEntry orderMainEntry = orderDataHandler.saveOrderMain(builder.build());

        // 开始配置订单项数据，保存订单项，并判断是否保存成功
        OrderLineVO.OrderLineVOBuilder itemBuilder = OrderLineVO.builder()
                .orderId(orderMainEntry.getOrderId())
                .orderNo(orderMainEntry.getOrderNo())
                .boardId(command.getBoardId())
                .commodityId(command.getCommodityId())
                .campaignId(marketingCommodity.getCampaignId())
                .title(commodity.getTitle())
                .subtitle(commodity.getSubtitle())
                .productPrice(commodity.getPrice())
                .sellPrice(marketingCommodity.getPrice())
                .createdBy(command.getCreatedBy());
        OrderLineItemEntry lineItemEntry = orderDataHandler.saveOrderLine(itemBuilder.build());
        Assert.notNull(lineItemEntry.getItemLineId(), "保存订单项失败。");

        // 设置配送地址信息并保存
        OrderAddressEntry orderAddressEntry = orderDataHandler.saveOrderAddress(
                OrderAddressVO.builder().orderId(orderMainEntry.getOrderId())
                        .addressId(command.getAddressId())
                        .consignee(addressEntry.getConsignee())
                        .province(addressEntry.getProvince())
                        .city(addressEntry.getCity())
                        .county(addressEntry.getCounty())
                        .phone(addressEntry.getPhone())
                        .postcode(addressEntry.getPostcode())
                        .address(addressEntry.getAddress())
                        .userId(command.getUserId()).build()
        );
        Assert.notNull(orderAddressEntry.getId(), "保存用户收货地址失败。");
        return orderMainEntry.getOrderId();
    }
}
